package com.wosai.register.repository.jdbc;

import java.sql.BatchUpdateException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;

import com.wosai.register.model.Price;
import com.wosai.register.repository.PriceRepository;
import com.wosai.register.util.ExceptionUtil;
import com.wosai.register.util.StringUtil;

@Repository
public class JdbcPriceRepository implements PriceRepository {
    private final static Log logger = LogFactory.getLog(JdbcPriceRepository.class);

    private NamedParameterJdbcTemplate npjt;
    private SimpleJdbcInsert sji;

    private final static String SELECT_BY_PRODUCT = "select * from PRICE where merchant_id = :merchantId  and product_id=:productId";
    private final static String SELECT_BY_TERMINAL = "select * from PRICE where merchant_id = :merchantId ";

    private final static String DELETE_BY_PRODUCT = "delete from PRICE where merchant_id = :merchantId  and product_id = :productId";
    private final static String DELETE_BY_TERMINAL = "delete from PRICE where merchant_id = :merchantId ";
    
    private final static String UPDATE = "update PRICE ";
    
    private final static String MARK_DELETE_BY_PRODUCT = "update PRICE set deleted=:deleted where merchant_id = :merchantId  and product_id = :productId";

    @Autowired
    public JdbcPriceRepository(DataSource dataSource) {
        this.sji = new SimpleJdbcInsert(dataSource)
                            .withTableName("PRICE");

        this.npjt = new NamedParameterJdbcTemplate(dataSource);
    }

    @Override
    public List<Price> findByProductId(String merchantId,
                                       String productId)
    {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("merchantId", merchantId);
        params.put("productId", productId);
        return this.npjt.query(SELECT_BY_PRODUCT, params, ParameterizedBeanPropertyRowMapper.newInstance(Price.class));
    }

    @Override
    public List<Price> findByTerminal(String merchantId) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("merchantId", merchantId);
        return this.npjt.query(SELECT_BY_TERMINAL, params, ParameterizedBeanPropertyRowMapper.newInstance(Price.class));
    }

    @Override
    public List<String> insertBatch(List<Price> prices) {
        SqlParameterSource[] batch = new SqlParameterSource[prices.size()];
        for(int i=0; i<batch.length; ++i)
            batch[i] = new BeanPropertySqlParameterSource(prices.get(i));

        ArrayList<String> failed = new ArrayList<String>();
        try{
            int[] rows = this.sji.executeBatch(batch);
            logger.info("batch inserted " + StringUtil.intArrayToString(rows));
        }catch(DataAccessException dae){
            List<Integer> failedIndices = ExceptionUtil.extractFailedStatements(dae);
            for(int i: failedIndices){
                failed.add(prices.get(i).getIdx());
            }
            logger.warn("error in batch insert " + failedIndices);
            logger.warn("detailed error info " + ExceptionUtils.getStackTrace(dae));
        }
        return failed;
    }

    @Override
    public List<String> updateBatch(List<Price> prices) {
        return null;
        /*
        SqlParameterSource[] batch = new SqlParameterSource[prices.size()];
        for(int i=0; i<batch.length; ++i)
            batch[i] = new BeanPropertySqlParameterSource(prices.get(i));

        int[] rows = this.npjt.batchUpdate(UPDATE, batch);
        logger.info("batch update " + rows);
        */
    }

    @Override
    public void deleteByProduct(String merchantId,
                                String productId)
    {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("merchantId", merchantId);
        params.put("productId", productId);
        
        int rows = this.npjt.update(DELETE_BY_PRODUCT, params);
        logger.info("deleted " + rows);
    }

    @Override
    public void deleteByTerminal(String merchantId) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("merchantId", merchantId);
        
        int rows = this.npjt.update(DELETE_BY_TERMINAL, params);
        logger.info("deleted " + rows);
    }

    @Override
    public void markDeleteByProduct(String merchantId,
                                    String productId) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("merchantId", merchantId);
        params.put("productId", productId);
        params.put("deleted", "1");
        
        int rows = this.npjt.update(MARK_DELETE_BY_PRODUCT, params);
        logger.info("mark deleted " + rows);
        // TODO Auto-generated method stub
        
    }

}
